﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CatalogImporter.Utils;
using DiArte.Data.Catalog;
using System.Transactions;
using System.Configuration;
using System.IO;

namespace CatalogImporter
{
    class Program
    {
        /// <summary>
        /// The categories set
        /// </summary>
        private static Dictionary<String, int> categories = new Dictionary<String, int>();

        /// <summary>
        /// The stores
        /// </summary>
        private static Dictionary<String, Store> stores = new Dictionary<String, Store>() {
            {"it", new Store(){ Country = "IT", Currency = "EUR", StoreId = 1, WallStickersCategoryName = "Adesivi da muro" }},
            {"en", new Store(){ Country = "GB", Currency = "EUR", StoreId = 2, WallStickersCategoryName = "Wall stickers"}}
        };

        static void Main(string[] args)
        {
            // Get the products enumerator
            var productsList = new ProductsList(args[0]);
            var enumerator = productsList.GetEnumerator();

            var attributes = new Dictionary<String, AttributeValues>();

            // Delete the catalog
            DeleteCatalog();

            // Parse attributes files
            attributes.Add("color", ParseAttribute(Path.Combine(Path.Combine(new FileInfo(args[0]).Directory.FullName, "colors.csv")), "color"));
            attributes.Add("size", GetSizeAttribute(args[0]));

            // Create the wall stickers category
            var wallStickersCategoryId = CreateWallStickersCategory();

            int row = 0;

            // Inserts the new products
            while (enumerator.MoveNext())
            {
                row++;

                var product = enumerator.Current;

                if (product == null)
                {
                    Console.WriteLine(String.Format("Il prodotto non è importabile. Riga {0}", row));

                    continue;
                }

                // Insert the category
                var categoryId = InsertCategory(product.Category);

                // Insert the product
                var productId = InsertProduct(product);

                // Insert product\category relation
                InsertProductCategoryRelation(productId, categoryId);
                InsertProductCategoryRelation(productId, wallStickersCategoryId);

                // Insert the product texts
                InsertLocalizeProductTexts(productId, product);

                // Insert the product prices
                InsertProductPrice(productId, product);

                // Insert product images
                InsertProductImages(productId, Path.Combine(new FileInfo(args[0]).Directory.FullName, "images"), product);

                // Insert product attributes
                ImportProductAttribute(productId, attributes["color"], new List<LocalizedItem<String>>() { 
                        new LocalizedItem<String>() { Value ="Colore", Language = "it" },
                        new LocalizedItem<String>() { Value ="Color", Language = "en" }
                    }, product.Colors);

                ImportProductAttribute(productId, attributes["size"], new List<LocalizedItem<String>>() { 
                        new LocalizedItem<String>() { Value ="Dimensione", Language = "it" },
                        new LocalizedItem<String>() { Value ="Size", Language = "en" }
                    }, product.Sizes);

                Console.WriteLine(String.Format("Il prodotto alla riga {0} è stato importato correttamente", row));
            }

            // Delete cache
            DeleteFolder(ConfigurationManager.AppSettings["CacheFolderPath"].ToString());
        }

        private static void ImportProductAttribute(int productId, AttributeValues attribute, List<LocalizedItem<String>> names, List<ProductAttribute> attributeValues)
        {
            // Insert the attribute
            var attributeDal = new AttributeDal();

            var attributeId = attributeDal.Insert(attribute.Type);

            // Insert localized names
            var localizedAttributeTextDal = new LocalizedAttributeTextDal();

            foreach (var name in names)
                localizedAttributeTextDal.Insert(attributeId, "name", name.Language, name.Value);

            // Insert product\attribute relation
            var productAttributeDal = new ProductAttributeDal();

            productAttributeDal.Insert(productId, attributeId);

            var isDefault = true;

            foreach (var attributeValue in attributeValues)
            {
                // Insert value
                var attributeValueDal = new AttributeValueDal();

                if (!attribute.Values.ContainsKey(attributeValue.Value))
                {
                    Console.WriteLine(String.Format("Impossibile trovare il valore {0} per l'attributo di tipo {0}. L'attributo non verrà importato", attributeValue.Value, attribute.Type));

                    return;
                }

                var attributeValueId = attributeValueDal.Insert(attributeId, attribute.Values[attributeValue.Value], attributeValue.Value, isDefault);

                // Insert localized text
                var localizedAttributeValueTextDal = new LocalizedAttributeValueTextDal();

                foreach (var name in attribute.Names[attributeValue.Value])
                    localizedAttributeValueTextDal.Insert(attributeValueId, "name", name.Language, name.Value);

                var attributeValuePriceDal = new AttributeValuePriceDal();

                foreach (var price in attributeValue.Price)
                {
                    var store = stores.First(value => { return value.Key.Equals(price.Language); }).Value;

                    attributeValuePriceDal.Insert(attributeValueId, store.StoreId,
                        price.Value, store.Currency);
                }

                isDefault = false;
            }
        }

        private static AttributeValues GetSizeAttribute(String productsFilePath)
        {
            Console.WriteLine("Sto recuperando le dimensioni");

            // Get the products enumerator
            var productsList = new ProductsList(productsFilePath);
            var enumerator = productsList.GetEnumerator();

            var sizeAttributeValues = new AttributeValues()
            {
                Type = "size",
                Names = new Dictionary<String, List<LocalizedItem<String>>>(),
                Values = new Dictionary<String, String>()
            };

            while (enumerator.MoveNext())
            {
                var product = enumerator.Current;

                if (product == null)
                    continue;

                product.Sizes.ForEach(size =>
                {
                    var sizeCode = GetSizeCode(size.Value);

                    if (!sizeAttributeValues.Values.ContainsKey(size.Value))
                    {
                        sizeAttributeValues.Values.Add(size.Value, sizeCode);
                        sizeAttributeValues.Names.Add(size.Value, new List<LocalizedItem<String>>() { 
                            new LocalizedItem<String>() {  Language = "it", Value = String.Format("{0} cm", size.Value)},
                            new LocalizedItem<String>() {  Language = "en", Value = String.Format("{0} cm", size.Value)}
                        });
                    }
                });
            }

            return sizeAttributeValues;
        }

        private static String GetSizeCode(String value)
        {
            var dimensions = value.Split(new char[] { 'x' });

            return String.Format("D{0}.{1}", dimensions[0].Trim(), dimensions[1].Trim());
        }

        private static AttributeValues ParseAttribute(String file, String type)
        {
            Console.WriteLine(String.Format("Sto importando il file {0}", file));

            var attributeValues = new AttributeValues()
            {
                Type = type,
                Names = new Dictionary<String, List<LocalizedItem<String>>>(),
                Values = new Dictionary<String, String>()
            };

            using (var attributesList = new AttributesList(file))
            {
                var enumerator = attributesList.GetEnumerator();

                // Insert the attribute values
                while (enumerator.MoveNext())
                {
                    var attribute = enumerator.Current;

                    if (attributeValues.Values.ContainsKey(attribute.Value))
                    {
                        Console.WriteLine(String.Format("Esiste già un attributo con codice {0}", attribute.Value));

                        continue;
                    }

                    attributeValues.Values.Add(attribute.Value, attribute.Code);
                    attributeValues.Names.Add(attribute.Value, attribute.Name.Select(name =>
                    {
                        return new LocalizedItem<String>() { Language = name.Language, Value = name.Value };
                    }).ToList());
                }
            }

            Console.WriteLine(String.Format("File {0} importato", file));

            return attributeValues;
        }

        private static int InsertProduct(Product product)
        {
            var productDal = new ProductDal();

            return productDal.Insert(product.Code, false, "wall_sticker");
        }

        private static void InsertProductCategoryRelation(int productId, int categoryId)
        {
            var productCategoryDal = new ProductCategoryDal();

            productCategoryDal.Insert(productId, categoryId);
        }

        private static void InsertProductPrice(int productId, Product product)
        {
            var productPriceDal = new ProductPriceDal();

            foreach (var price in product.Price)
            {
                var store = stores[price.Language];

                productPriceDal.Insert(productId, store.StoreId, price.Value, store.Currency);
            }
        }

        private static void InsertProductImages(int productId, String imagesPath, Product product)
        {
            var baseImagesPath = ConfigurationManager.AppSettings["BaseImagesPath"].ToString();
            var pathToProductImages = Path.Combine(imagesPath, product.Name.First(name => { return "it".Equals(name.Language); }).Value);
            var imagesFolderPath = Path.Combine(ConfigurationManager.AppSettings["ImagesFolderPath"].ToString(), productId.ToString());

            var productImageDal = new ProductImageDal();

            foreach (var language in stores.Keys)
            {
                // Create the image folder for the product
                Directory.CreateDirectory(Path.Combine(imagesFolderPath, language));

                // Default image
                File.Copy(Path.Combine(pathToProductImages, language, "default.jpg"), Path.Combine(imagesFolderPath, language, "default.jpg"));
                productImageDal.Insert(productId, language, "default", String.Format(@"{0}/{1}/{2}/default.jpg", baseImagesPath, productId, language));

                // Detail main image
                File.Copy(Path.Combine(pathToProductImages, language, "detail_main.jpg"), Path.Combine(imagesFolderPath, language, "detail_main.jpg"));
                productImageDal.Insert(productId, language, "detail_main", String.Format(@"{0}/{1}/{2}/detail_main.jpg", baseImagesPath, productId, language));

                // Basket image
                File.Copy(Path.Combine(pathToProductImages, language, "default.jpg"), Path.Combine(imagesFolderPath, language, "basket.jpg"));
                productImageDal.Insert(productId, language, "basket", String.Format(@"{0}/{1}/{2}/basket.jpg", baseImagesPath, productId, language));

                // Detail carousel images
                var i = 0;

                foreach (var file in new DirectoryInfo(Path.Combine(pathToProductImages, language)).GetFiles("detail_carousel_*"))
                {
                    productImageDal.Insert(productId, language, "detail_carousel", String.Format(@"{0}/{1}/{2}/detail_carousel_{3}.jpg", baseImagesPath, productId, language, i));

                    File.Copy(Path.Combine(pathToProductImages, language, file.Name), Path.Combine(imagesFolderPath, language, String.Format("detail_carousel_{0}.jpg", i)));

                    i++;
                }
            }
        }

        private static int InsertCategory(List<LocalizedItem<String>> names)
        {
            var keyName = names.First().Value;

            if (categories.ContainsKey(keyName))
                return categories[keyName];

            var categoryDal = new CategoryDal();

            var categoryId = categoryDal.Insert(String.Format("ws_{0}", categories.Count + 1), String.Format("1.{0}.", categories.Count));

            var localizedCategoryTextDal = new LocalizedCategoryTextDal();

            foreach (var language in stores.Keys)
            {
                var name = names.First(localizedName => { return localizedName.Language.Equals(language); });

                localizedCategoryTextDal.Insert(categoryId, "name", language, name.Value);
                localizedCategoryTextDal.Insert(categoryId, "alias", language, name.Value.ToLower().Replace(' ', '_'));
            }

            categories.Add(keyName, categoryId);

            return categoryId;
        }

        private static void InsertLocalizeProductTexts(int productId, Product product)
        {
            var localizedProductTextDal = new LocalizedProductTextDal();

            foreach (var name in product.Name)
                localizedProductTextDal.Insert(productId, "name", name.Language, name.Value);

            foreach (var description in product.Description)
                localizedProductTextDal.Insert(productId, "description", description.Language, description.Value);

            foreach (var alias in product.Shortcut)
                localizedProductTextDal.Insert(productId, "alias", alias.Language, alias.Value);
        }

        private static void DeleteCatalog()
        {
            var basketItemDal = new BasketItemDal();

            basketItemDal.DeleteAll();

            var basketDal = new BasketDal();

            basketDal.DeleteAll();

            var productCategoryDal = new ProductCategoryDal();

            productCategoryDal.DeleteAll();

            var localizedCategoryTextDal = new LocalizedCategoryTextDal();

            localizedCategoryTextDal.DeleteAll();

            var categoryDal = new CategoryDal();

            categoryDal.DeleteAll();

            var productImageDal = new ProductImageDal();

            productImageDal.DeleteAll();

            var productPriceDal = new ProductPriceDal();

            productPriceDal.DeleteAll();

            var productAttributeDal = new ProductAttributeDal();

            productAttributeDal.DeleteAll();

            var localizedProductTextDal = new LocalizedProductTextDal();

            localizedProductTextDal.DeleteAll();

            var productDal = new ProductDal();

            productDal.DeleteAll();

            // Delete attributes
            var localizedAttributeTextDal = new LocalizedAttributeTextDal();

            localizedAttributeTextDal.DeleteAll();

            var localizedAttributeValueTextDal = new LocalizedAttributeValueTextDal();

            localizedAttributeValueTextDal.DeleteAll();

            var attributeValuePriceDal = new AttributeValuePriceDal();

            attributeValuePriceDal.DeleteAll();

            var attributeValueDal = new AttributeValueDal();

            attributeValueDal.DeleteAll();

            var attributeDal = new AttributeDal();

            attributeDal.DeleteAll();

            // Delete product images folder
            DeleteFolder(ConfigurationManager.AppSettings["ImagesFolderPath"].ToString());
        }

        private static void DeleteFolder(string folderPath)
        {
            foreach (var folder in new DirectoryInfo(folderPath).GetDirectories())
            {
                foreach (var subFolder in folder.GetDirectories())
                    foreach (var file in subFolder.GetFiles())
                        file.Delete();

                folder.Delete(true);
            }
        }

        private static int CreateWallStickersCategory()
        {
            var categoryDal = new CategoryDal();

            var localizedCategoryTextDal = new LocalizedCategoryTextDal();

            // Insert the default wall stickers category
            var categoryId = categoryDal.Insert("ws", "1.");

            foreach (var store in stores)
            {
                localizedCategoryTextDal.Insert(categoryId, "name", store.Key, store.Value.WallStickersCategoryName);
                localizedCategoryTextDal.Insert(categoryId, "alias", store.Key, store.Value.WallStickersCategoryName.ToLower().Replace(' ', '_'));
            }

            return categoryId;
        }
    }
}
